package nl.weeaboo.sh.editor.area;

import java.awt.BorderLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JComponent;
import javax.swing.JPanel;

import nl.weeaboo.sh.model.AreaModel;
import nl.weeaboo.sh.model.RoomModel;
import timon.common.components.DirectValidationField;
import timon.common.components.property.PropertyModel;
import timon.common.components.property.PropertyPanel;
import timon.common.components.property.editor.StringPropertyEditor;

@SuppressWarnings("serial")
public class RoomEditor extends JPanel {

	private AreaModel area;
	private RoomModel selectedRoom;
	private List<ChangeListener> listeners;
	
	private DirectValidationField idField;
	private JComponent mainPanel;
	private PropertyPanel propertyPanel;
	private PropertyModel propertyModel;
	
	public RoomEditor() {
		listeners = new LinkedList<ChangeListener>();
		
		propertyPanel = new PropertyPanel();
		
		idField = new DirectValidationField() {
			protected boolean isValid(String text) {
				if (area == null || selectedRoom == null) return true;
				return text.equals(selectedRoom.getId()) || area.getRoom(text) == null;
			}
			protected void onValidTextEntered(String text) {
				if (selectedRoom == null) return;
				selectedRoom.setId(text);
			}			
		};

		setLayout(new BorderLayout(5, 5));
		add(mainPanel = createMainPanel(), BorderLayout.CENTER);
		
		mainPanel.setVisible(false);
	}
	public void dispose() {
		propertyPanel.dispose();
	}
	
	//Functions		
	protected JPanel createMainPanel() {
		JPanel panel = new JPanel(new BorderLayout(5, 5));
		panel.add(propertyPanel, BorderLayout.NORTH);
		return panel;
	}
	
	public void addChangeListener(ChangeListener l) {
		listeners.add(l);
	}
	public void removeChangeListener(ChangeListener l) {
		listeners.remove(l);
	}
	
	protected void fireRoomChanged(final RoomModel room) {
		ChangeListener ls[] = listeners.toArray(new ChangeListener[listeners.size()]);
		for (ChangeListener l : ls) {
			l.onChanged(room);
		}
	}

	//Getters
	public RoomModel getSelectedRoom() {
		return selectedRoom;
	}
	
	//Setters
	public void setSelectedRoom(AreaModel area, RoomModel model) {
		this.area = area;
		
		if (selectedRoom != model) {		
			selectedRoom = model;

			mainPanel.setVisible(selectedRoom != null);			
			
			propertyModel = new PropertyModel();
			if (selectedRoom != null) {
				propertyModel.addProperty("RoomModel.id", "ID", selectedRoom.getId(), String.class);				
				propertyModel.addProperty("RoomModel.x", "X", selectedRoom.getX(), Integer.class);				
				propertyModel.addProperty("RoomModel.y", "Y", selectedRoom.getY(), Integer.class);				
				propertyModel.addProperty("RoomModel.width", "Width", selectedRoom.getWidth(), Integer.class);				
				propertyModel.addProperty("RoomModel.height", "Height", selectedRoom.getHeight(), Integer.class);				
				propertyModel.addProperty("RoomModel.openLeft", "Open Left", selectedRoom.isLeftOpen(), Boolean.class);				
				propertyModel.addProperty("RoomModel.openRight", "Open Right", selectedRoom.isRightOpen(), Boolean.class);				
				propertyModel.addProperty("RoomModel.openTop", "Open Top", selectedRoom.isTopOpen(), Boolean.class);				
				propertyModel.addProperty("RoomModel.openBottom", "Open Bottom", selectedRoom.isBottomOpen(), Boolean.class);				
				propertyModel.addProperty("RoomModel.wallLeft", "Wall Left", selectedRoom.isLeftWall(), Boolean.class);				
				propertyModel.addProperty("RoomModel.wallRight", "Wall Right", selectedRoom.isRightWall(), Boolean.class);
				propertyModel.addProperty("RoomModel.wallTop", "Wall Top", selectedRoom.isTopWall(), Boolean.class);				
				propertyModel.addProperty("RoomModel.wallBottom", "Wall Bottom", selectedRoom.isBottomWall(), Boolean.class);				

				propertyModel.setEditor("RoomModel.id", new StringPropertyEditor(idField));				
			}
			propertyPanel.setModel(propertyModel);									
			propertyModel.addPropertyListener(new PropertyModelListener(selectedRoom));
		}
	}
	
	//Inner Classes
	private class PropertyModelListener implements PropertyChangeListener {
		
		private final RoomModel selectedRoom;
		
		public PropertyModelListener(RoomModel selectedRoom) {
			this.selectedRoom = selectedRoom;
		}
		
		public void propertyChange(PropertyChangeEvent event) {
			if (selectedRoom == null) {
				return;
			}
			
			boolean leftOpen = selectedRoom.isLeftOpen();
			boolean rightOpen = selectedRoom.isRightOpen();
			boolean topOpen = selectedRoom.isTopOpen();
			boolean bottomOpen = selectedRoom.isBottomOpen();
			boolean leftWall = selectedRoom.isLeftWall();
			boolean rightWall = selectedRoom.isRightWall();
			boolean topWall = selectedRoom.isTopWall();
			boolean bottomWall = selectedRoom.isBottomWall();
			
			String pname = event.getPropertyName();
			if ("RoomModel.id".equals(pname)) {
				selectedRoom.setId((String)event.getNewValue());
			} else if ("RoomModel.x".equals(pname)) {
				selectedRoom.setOffset((Integer)event.getNewValue(), selectedRoom.getY());
			} else if ("RoomModel.y".equals(pname)) {
				selectedRoom.setOffset(selectedRoom.getX(), (Integer)event.getNewValue());
			} else if ("RoomModel.width".equals(pname)) {
				selectedRoom.setSize((Integer)event.getNewValue(), selectedRoom.getHeight());
			} else if ("RoomModel.height".equals(pname)) {
				selectedRoom.setSize(selectedRoom.getWidth(), (Integer)event.getNewValue());
			} else if ("RoomModel.openLeft".equals(pname)) {
				leftOpen = (Boolean)event.getNewValue();
			} else if ("RoomModel.openRight".equals(pname)) {
				rightOpen = (Boolean)event.getNewValue();
			} else if ("RoomModel.openTop".equals(pname)) {
				topOpen = (Boolean)event.getNewValue();
			} else if ("RoomModel.openBottom".equals(pname)) {
				bottomOpen = (Boolean)event.getNewValue();
			} else if ("RoomModel.wallLeft".equals(pname)) {
				leftWall = (Boolean)event.getNewValue();
			} else if ("RoomModel.wallRight".equals(pname)) {
				rightWall = (Boolean)event.getNewValue();
			} else if ("RoomModel.wallTop".equals(pname)) {
				topWall = (Boolean)event.getNewValue();
			} else if ("RoomModel.wallBottom".equals(pname)) {
				bottomWall = (Boolean)event.getNewValue();
			}			
			selectedRoom.setOpenSides(leftOpen, rightOpen, topOpen, bottomOpen);
			selectedRoom.setWallSides(leftWall, rightWall, topWall, bottomWall);
			
			fireRoomChanged(selectedRoom);
		}
	}

}
